﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
using WikiMarkupConverter.RegexModels;

namespace WikiMarkupConverter
{

    /// <summary>
    /// Provides helper methods to interact with the Syntax XML file
    /// </summary>
    internal class XmlFileHelper
    {
        private const string MarkupXmlFile = "./markups.xml";
        private static List<Syntax> _syntaxs;

        /// <summary>
        /// Get the cached list of Syntaxes, if the list is not yet in memory it will be loaded from the XML
        /// </summary>
        /// <returns></returns>
        internal static async Task<List<Syntax>> GetSyntaxesAsync()
        {
            return _syntaxs ?? (_syntaxs = await LoadXmlAsync());
        }

        /// <summary>
        /// Retreives all the syntaxes stored in the markup.xml file.
        /// </summary>
        /// <returns></returns>
        private static async Task<List<Syntax>> LoadXmlAsync()
        {
            if (!File.Exists(MarkupXmlFile))
                File.Create(MarkupXmlFile);

            var syntaxes = new List<Syntax>();
            await Task.Run(() =>
            {
                var xDoc = XDocument.Load(MarkupXmlFile);

                foreach (var syntaxGroup in xDoc.Descendants("syntax").GroupBy(e => e.Attribute("name")))
                {
                    var syntax = new Syntax { Name = syntaxGroup.Key.Value };

                    foreach (var markupNode in syntaxGroup.Descendants("markup"))
                    {
                        // Getting markup type
                        Markup markup;
                        var strType = markupNode.Attribute("type").Value;
                        Markup.MarkupType type;
                        Enum.TryParse(strType, true, out type);

                        // Creating corresponding markup
                        if (type == Markup.MarkupType.MultiLine)
                            markup = new MultiLineMarkup { Name = markupNode.Attribute("name").Value };
                        else
                            markup = new SingleLineMarkup { Name = markupNode.Attribute("name").Value };


                        foreach (var regexNode in markupNode.Descendants("regex"))
                        {
                            if (markup is MultiLineMarkup)
                            {
                                var regex = new MultiLineRegex
                                    {
                                        FromOpeningTag = regexNode.Descendants("fromOpening").First().Value,
                                        FromClosingTag = regexNode.Descendants("fromClosing").First().Value,
                                        FromInsideLine = regexNode.Descendants("fromInside").First().Value,
                                        ToOpeningTag = regexNode.Descendants("toOpening").First().Value,
                                        ToClosingTag = regexNode.Descendants("toClosing").First().Value,
                                        ToInsideLine = regexNode.Descendants("toInside").First().Value
                                    };
                                markup.MultiLineRegexes.Add(regex);
                            }
                            else
                            {
                                var regex = new SingleLineRegex
                                    {
                                        From = regexNode.Descendants("from").First().Value,
                                        To = regexNode.Descendants("to").First().Value
                                    };
                                markup.InlineRegexes.Add(regex);
                            }
                        }

                        syntax.Markups.Add(markup);
                    }

                    syntaxes.Add(syntax);
                }
            });
            return syntaxes;
        }
    }
}
